; filename ******** lcd.asm ************** 
; Put your Lab 6 solution here
; comment

  absentry   LCD_Open
  absentry   LCD_OutChar
  absentry   LCD_Clear
  absentry   LCD_GoTo
  absentry   LCD_OutDec
  absentry   LCD_OutFix
  absentry   LCD_OutString
  absentry   Timer_Init
  
          ;org $2000
RAM:          section

TEMP1     ds.w 1

WAIT100US ds.w 1

WAIT90US  ds.w 1
 

EEPROM:       section ;          org $4000

PTH       equ $0260

DDRH      equ $0262

PTP       equ $0258

DDRP      equ $025A

TSCR1     equ $0046

TSCR2     equ $004D

TCNT      equ $0044 
; 0 for 8 MHz and 1 for 24 MHz

FREQ      equ 1

; how many timer cycles to reach 100 us at each frequency

WAIT100US_8   equ 7

WAIT100US_24  equ 19 
WAIT90US_8    equ 6

WAIT90US_24   equ 18 
; each counted in how many multiples of 100 us

TWENTYMS      equ 200

FIVEMS        equ 50

ONESIXFOUR    equ 17 
; to convert from digit to its char equivalent

ITOC          equ 48 
; some characters that are used

POINT         equ 46 ;'.'

CH0           equ 48 ;'0' 
;---------------------Timer_Init----------------------

; initialize the timer

; Input: none

;Output: none

;Registers modified: CCR

Timer_Init

      pshd

      movb #$80,TSCR1

      movb #$07,TSCR2

      ldd #0

      cpd #FREQ

      beq EGT

      ; here if set to 24 MHz

      ldd #WAIT100US_24

      std WAIT100US

      ldd #WAIT90US_24

      std WAIT90US

      bra EINIT

EGT ldd #WAIT100US_8

      std WAIT100US

      ldd #WAIT90US_8

      std WAIT90US 

EINIT puld

      rts 
;---------------------Timer_Wait--------------------

; wait a specified amount of cycles each cycles lasts 16 us at 8 MHz and 5.33 us at 24 MHz

; Input: register D has number of cycles

; Outputs: none

; Errors: register D must be <= 32767

Timer_Wait

      pshd ; save d

      addd TCNT

wait cpd TCNT

      bpl wait

      puld ; restore d

      rts 
;---------------------Timer_Wait_100US-----------

; waits 100 microseconds

; Input: register D

; Output: none

Timer_Wait_100US

      pshd

      ldd WAIT100US

      jsr Timer_Wait

      puld

      rts 
Timer_Wait_100MS

      pshd

      ldd #63 
      jsr Timer_Wait

      puld

      rts 
       
;---------------------Timer_Wait_90US-----------

; waits 90 microseconds

; Input: register D

; Output: none

Timer_Wait_90US

      pshd

      ldd WAIT90US

      jsr Timer_Wait

      puld

      rts 
 

;--------------------Timer_Wait_Mult-------------

; waits a multiple of 100 microseconds

; Input: register D holds the number of times to wait 100 us

; Output: none

Timer_Wait_Mult

      pshd

waitm cpd #0

      beq endwm

      jsr Timer_Wait_100US

      addd #-1

      bra waitm

endwm puld

      rts 
;--------------- outCsrNibble ------------------

; sends 4 bits to the LCD control/status

; Input: RegA is 4-bit command, in bit positions 3,2,1,0 of RegA

; Output: none

outCsrNibble

      ; save

      pshd

      ldab PTH

      ; B holds only RS bit

      andb #$01

      stab TEMP1

      ; shift bits 3-0 over to bits 7-4

      lsla

      lsla

      lsla

      lsla

      ; RS bit restored

      oraa TEMP1

      ; RS whatever it was and E cleared, set new PTH4-7 values

      staa PTH

      ; delay at least 195 ns

      psha

      pula

      psha

      pula

      ; set E

      ldaa PTH

      oraa #$02

      staa PTH

      ; delay some more at least 10 ns

      psha

      pula

      ; clear E

      anda #$FD

      staa PTH

      ; restore

      puld

      rts 
;---------------------outCsr---------------------

; sends one command code to the LCD control/status

; Input: RegA is 8-bit command to execute

; Output: none

outCsr

      pshd

      ; clear RS bit

      ldab PTH

      andb #$FE

      stab PTH

      tfr A,B

      ; put most significant bits in least significant bit place

      lsra

      lsra

      lsra

      lsra

      jsr outCsrNibble

      tfr B,A

      jsr outCsrNibble

      jsr Timer_Wait_90US

      puld

      rts 
;---------------------LCD_Open---------------------

; initialize the LCD display, called once at beginning

; Input: none

; Output: none

; Registers modified: CCR 

LCD_Open
      pshd

      ; wait 20 ms

      ldab PTH

      andb #$FE

      stab PTH

      ldd #TWENTYMS

      ;jsr Timer_Wait_Mult

      ; initialize direction register

      ldaa #$FF

      staa DDRH

      ldaa #$03

      jsr outCsrNibble

      ; wait 5 ms

      ldd #FIVEMS

      ;jsr Timer_Wait_Mult

      ldaa #$03

      jsr outCsrNibble

      ; wait 100 us

      jsr Timer_Wait_100US

      ldaa #$03

      jsr outCsrNibble

      ; wait 100 us

      jsr Timer_Wait_100US

      ldaa #$02

      jsr outCsrNibble

      jsr Timer_Wait_100US

      ldaa #$28

      jsr outCsr

      ldaa #$14

      jsr outCsr

      ldaa #$06

      jsr outCsr

      ldaa #$0C

      jsr outCsr

      puld

      rts 
;---------------------LCD_Clear---------------------

; clear the LCD display, send cursor to home

; Input: none

; Outputs: none

; Registers modified: CCR

LCD_Clear

      psha

      ldaa #$01

      jsr outCsr

      ldd #ONESIXFOUR

      jsr Timer_Wait_Mult

      ldaa #$01

      jsr outCsr

      ldd #ONESIXFOUR

      jsr Timer_Wait_Mult

      pula

      rts 
;---------------------LCD_OutChar---------------------

; sends one ASCII to the LCD display

; Input: RegD (call by value) letter is 8-bit ASCII code

; Outputs: none

; Registers modified: CCR

LCD_OutChar

      pshd

      ; set RS

      ldaa PTH

      oraa #$01

      staa PTH 
      tfr B,A

      ; put most significant bits in least significant bit place

      lsra

      lsra

      lsra

      lsra

      jsr outCsrNibble

      tfr B,A

      jsr outCsrNibble

      jsr Timer_Wait_90US

      puld

      rts 
;-----------------------LCD_GoTo-----------------------

; Move cursor (set display address)

; Input: RegD is display address is 0 to 7, or $40 to $47

; Output: none

; errors: it will check for legal address

LCD_GoTo

      pshd

      ; test if in range $08-$3F

      cmpb #$08

      bhs tst1

      bra good

tst1 cmpb #$3F

      bls err

      ; test if in range $48-$FF

tst2 cmpb #$48

      bhs tst3

      bra good

tst3 cmpb #$FF

      bls err

good tfr B,A

      adda #$80

      jsr outCsr

err puld

      rts 
; ---------------------LCD_OutString-------------

; Output character string to LCD display, terminated by a NULL(0)

; Inputs: RegD (call by reference) points to a string of ASCII characters

; Outputs: none

; Registers modified: CCR

LCD_OutString

      pshx

      pshd

      tfr D,X

      clra

loopos ldab 1,X+

      beq end

      jsr LCD_OutChar

      bra loopos

end puld

      pulx

      rts 
N equ 0

;-----------------------LCD_OutDec-----------------------

; Output a 16-bit number in unsigned decimal format

; Input: RegD (call by value) 16-bit unsigned number

; Output: none

; Registers modified: CCR

LCD_OutDec

      pshx

      pshd

      ; allocate store variable / allocate space

      pshd 
begdec cpd #10

      blo print

      ldx #10

      ;D/X --> X  ;Remainder -->D

      idiv

      ; store remainder value
      
      std 0,SP

      tfr X,D

      jsr LCD_OutDec 
print ldd 0,SP

      addd #ITOC

      jsr LCD_OutChar

      ; clean up

      ins

      ins

      puld

      pulx

      rts 
ERRS fcb "*.**",0

; -----------------------LCD_OutFix----------------------

; Output characters to LCD display in fixed-point format

; unsigned decimal, resolution 0.01, range 0.00 to 9.99

; Inputs: RegD is an unsigned 16-bit number

; Outputs: none

; Registers modified: CCR

; E.g., RegD=0, then output "0.00 "

; RegD=3, then output "0.03 "

; RegD=89, then output "0.89 "

; RegD=123, then output "1.23 "

; RegD=999, then output "9.99 "

; RegD>999, then output "*.** "

LCD_OutFix

      pshx

      pshd

      cpd #999

      ; if number is above 999 we want to print *.**

      bhi outor

      ; we know number is in range if here

      ldx #100

      ;D/X --> X; Remainder --> D

      idiv

      exg X,D

      ; print out big part

      jsr LCD_OutDec

      exg X,D

      ; print out decimal part

      pshd

      ldd #POINT

      jsr LCD_OutChar

      puld

      cpd #10

      ; if decimal part is less than 10 go to small

      blo small

      ; here if decimal is between 10 and 99

      jsr LCD_OutDec

      bra end

small pshd

      ldd #CH0

      jsr LCD_OutChar

      puld

      jsr LCD_OutDec

      bra endof

      ; prints *.**

outor ldd #ERRS

      jsr LCD_OutString

endof puld

      pulx

      rts 

EEPROM:       section